package com.project.security;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.project.common.ConfigBean;
import com.project.common.Constants;
import com.project.entity.sys.Permissions;
import com.project.entity.sys.Role;
import com.project.entity.sys.User;
import com.project.service.sys.UserService;
import com.project.service.sys.RoleService;
import com.project.util.ListUtil;
import com.project.util.SpringContextUtil;

/**
 * shiro权限控制
 * @author
 *
 */
@Component
public class SecurityRealm extends AuthorizingRealm {
	
	@Autowired
	public ConfigBean configBean;
	
	public static Map<String,List<Role>> roleMap = new HashMap<>();
	
	 /**
	  * 每次进行权限校验时调用
	  * 该方法被调用时，根据当前登录用户查询出所属角色以及权限并且装载
	  */
    @Override  
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals){  
        //获取当前登录的用户名,等价于(String)principals.fromRealm(this.getName()).iterator().next()  
    	String currentUsername = (String)super.getAvailablePrincipal(principals);  
    	Set<String> roleNames = new HashSet<String>();  
    	Set<String> permissions = new HashSet<String>();
    	if(configBean.getSystemCode().equals(currentUsername)){//如果当前登录人为系统管理员，则开放所有权限
    		RoleService roleService = (RoleService) SpringContextUtil.getBean("roleService");
    		
    		List<Role> roles = roleService.queryList();
    		List<Permissions> pss = roleService.getAllPermissions();
    		
    		for(Role role :roles){
    			roleNames.add(role.getRoleCode());
    		}
    		
    		for(Permissions ps :pss){
    			permissions.add(ps.getElement());
    		}
    		
    		
    	}else{
    		UserService userService = (UserService) SpringContextUtil.getBean("userService");
    		
    		//List<Role> roles = userService.getRolsByUserCode(currentUsername);
    		List<Role> roles = SecurityRealm.roleMap.get(currentUsername);
        	if(ListUtil.isNotEmpty(roles)){
        		/*装载角色*/
        		for(Role role:roles){
        			roleNames.add(role.getRoleCode());
        			
        			/*装载角色下的所有权限*/
        			List<Permissions> rP =  role.getPermissions();
        			
        			if(ListUtil.isNotEmpty(rP)){
        				for(Permissions p:rP){
        					permissions.add(p.getElement());
        				}
        			}
        		}
        	}
    	}
    	
    	//对比的过程  
    	SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roleNames);  
    	info.setStringPermissions(permissions);  
    	return info;  

    }  
   
       
    /** 
     * 验证当前登录的Subject 
     * 该方法的调用时机为LoginController.login()方法中执行Subject.login()时 
     */  
    @Override  
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {  
        UsernamePasswordToken token = (UsernamePasswordToken)authcToken;  
        UserService userService = (UserService) SpringContextUtil.getBean("userService");
        User user = userService.getByUsername(token.getUsername());
        
        if(null != user){
        	if(Constants.STATUS_CLOSE.equals(user.getStatus())){//判断是否启用
        		throw new LockedAccountException();
        	}
    	  
        	AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(user.getUserCode(), user.getPassword(), user.getName());  
	        this.setSession("currentUser", user);  
	        this.setSession("currentUserName", user.getUserCode());  
	        return authcInfo;  
        }else{  
          return null;  
        }  
    }  
       
       
    /** 
     * 将一些数据放到ShiroSession中,以便于其它地方使用 
     * Controller,使用时直接用HttpSession.getAttribute(key)就可以取到 
     */  
    private void setSession(Object key, Object value){  
        Subject currentUser = SecurityUtils.getSubject();  
        if(null != currentUser){  
            Session session = currentUser.getSession();  
            if(null != session){  
                session.setAttribute(key, value);  
            }  
        }  
    }  


}
